package fem2;

import java.io.IOException;

import fem2.enu.StressType;
import fem2.observer.GidDisplacementObserver;
import fem2.observer.GidResistantObserver;
import fem2.observer.GidStressObserver;
import fem2.observer.TimeStepObserver;
import fem2.observer.TimingObserver;
import fem2.pre_and_post.GidPostStructural;
import fem2.strategies.Strategy;

/**
 * Abstract class for all structural demo with homogeneous material
 * 
 * @author hbui
 * 
 */
public abstract class AbstractStructuralStaticDemo extends AbstractDemoWithGiD {

	/**
	 * create material
	 * 
	 * @return
	 */
	public abstract MaterialModel createMaterial(Model m);

	/**
	 * specify element associated with model
	 * 
	 * @param mp
	 * @param mm
	 * @return
	 */
	public abstract Element createElement(MeshPart mp, MaterialModel mm);

	public Model createModel() {

		Mesh mesh = createMesh();

		Model m = new Model(mesh);

		MaterialModel mm = createMaterial(m);

		int dim = mesh.getDimension();
		if (dim == 1) {
			for (int i = 0; i < mesh.countEdges(); i++) {
				Element e = createElement(mesh.getEdge(i), mm);
				m.addElement(e);
			}
		} else if (dim == 2) {
			for (int i = 0; i < mesh.countFaces(); i++) {
				Element e = createElement(mesh.getFace(i), mm);
				m.addElement(e);
			}
		} else if (dim == 3) {
			for (int i = 0; i < mesh.countBlocks(); i++) {
				Element e = createElement(mesh.getBlock(i), mm);
				m.addElement(e);
			}
		} else {
			throw new Error("invalid dimension");
		}

		m = createConditions(m);

		/*
		 * set the number of fields for structural problem
		 */
		mesh.setNumberOfFields(mesh.getDimension());

		return m;
	}

	/**
	 * post process to Gid
	 * 
	 * @param m
	 * @param projGidDir
	 * @param projGidName
	 * @param meshFileName
	 */
	public void postProcess(Model m, String projGidDir, String projGidName, String meshFileName) {
		GidPostStructural post = new GidPostStructural(projGidDir, projGidName, meshFileName);
		post.clearAllPostFiles();
		// post.clearAllPostFiles(meshFileName);
		try {
			post.writeMesh(m, 0);
			post.writeNodalDisplacementResults(m, 0);
			post.writeGaussPointStressResults(m, 0, StressType.CAUCHY_STRESS);
		} catch (IOException e) {
			throw new Error("Write failed: " + e.getMessage());
		}
		// post.moveAllPostFiles(meshFileName);
	}

	/**
	 * add observers to the strategy. Override this method for specific
	 * requirements
	 * 
	 * @param s
	 */
	public void addObservers(Model m, Strategy s, TimeStepObserver o) {
		addFundamentalObservers(m, s, o);
	}

	/**
	 * @param m
	 * @param s
	 * @param o
	 * @throws Error
	 */
	protected void addFundamentalObservers(Model m, Strategy s, TimeStepObserver o) throws Error {
		if (meshFileName == null) {
			throw new Error("mesh file name was not set");
		}

		/*
		 * clean all previous post files
		 */
		String meshName = StringUtilities.getFileName(meshFileName);

		GidPostStructural post = new GidPostStructural(projectDir, projectName, meshName);
		post.clearAllPostFiles();

		Observer so = new GidStressObserver(m, o, projectDir, projectName, meshName);

		// Observer ro1 = new ResistantGraphicalObserver(m, s,
		// getNodesForResistantObserver(m));
		Observer ro2 = new GidResistantObserver(m, o, projectDir, projectName, meshName);

		Observer do1 = new GidDisplacementObserver(m, o, projectDir, projectName, meshName);

		s.addObserver(so);
		// s.addObserver(ro1);
		s.addObserver(ro2);
		s.addObserver(do1);
		s.addObserver(new TimingObserver());
	}

}
